//
//  HTRefreshScrollView.swift
//  MagaCore
//
//  Created by MrMessy on 2023/5/20.
//

import SwiftUI

struct HTRefreshScrollView<Content: View>: View {
  @State private var var_preOffset: CGFloat = 0
  @State private var var_offset: CGFloat = 0
  @State private var var_frozen = false
  @State private var var_rotation: Angle = .degrees(0)
  @State private var var_updateTime: Date = Date()
  var var_offDown : CGFloat = 0.0 // 滑动内容总高
  var var_listH : CGFloat = 0.0 // 列表高度
  var var_threshold: CGFloat = 70
  @Binding var var_showRefresh: Bool
  @Binding var var_isRefreshing: Bool // 下拉刷新
  @Binding var var_isMore: Bool // 加载更多
  @Binding var var_isNoMore: Bool
  let var_content: Content

  // 下拉刷新出发回调
  var var_refreshTrigger: (() -> Void)?
  // 上拉加载更多
  var var_moreTrigger: (() -> Void)?

  init(_ var_threshold: CGFloat = 70, var_offDown: CGFloat, var_listH: CGFloat, var_showRefresh: Binding<Bool>, refreshing: Binding<Bool>, var_isMore: Binding<Bool>, var_isNoMore: Binding<Bool>, var_refreshTrigger: @escaping () -> Void, var_moreTrigger: @escaping () -> Void, @ViewBuilder var_content: () -> Content) {
    self.var_threshold = var_threshold
    self._var_showRefresh = var_showRefresh
    self._var_isRefreshing = refreshing
    self.var_content = var_content()
    self.var_refreshTrigger = var_refreshTrigger
    self.var_moreTrigger = var_moreTrigger
    self._var_isMore = var_isMore
    self._var_isNoMore = var_isNoMore
    self.var_offDown = var_offDown
    self.var_listH = var_listH
  }

  var body: some View {
    VStack {
      ScrollView {
        ZStack(alignment: .top) {
          MovingPositionView()
          VStack {
            self.var_content
              .alignmentGuide(.top, computeValue: { _ in
                (self.var_isRefreshing && self.var_frozen) ? -self.var_threshold : 0
              })
          }

          if (var_showRefresh) {
            HTRefreshHeader(var_height: self.var_threshold,
                          var_loading: self.var_isRefreshing,
                          var_frozen: self.var_frozen,
                          var_rotation: self.var_rotation,
                          var_updateTime: self.var_updateTime)
          }
        }

        if var_isMore && !var_isRefreshing{
          HTRefreshMore(var_height: var_threshold).onAppear(){
            if nil != var_moreTrigger{
              var_moreTrigger!()
            }
          }
        }
      }
      .background(FixedPositionView())
      .onPreferenceChange(HTRefreshPreferenceTypes.HTRefreshPreferenceKey.self) { values in
        self.ht_calculate(values)
      }
      .onChange(of: var_isRefreshing) { refreshing in
        DispatchQueue.main.async {
          if !refreshing {
            self.var_updateTime = Date()
          }
        }
      }
    }
  }

  func ht_calculate(_ values: [HTRefreshPreferenceTypes.HTRefreshPreferenceData]) {
    DispatchQueue.main.async {
      /// 计算croll offset
      let movingBounds = values.first(where: { $0.var_viewType == .htEnumMovingPositionView })?.var_bounds ?? .zero
      let fixedBounds = values.first(where: { $0.var_viewType == .htEnumFixedPositionView })?.var_bounds ?? .zero
      self.var_offset = movingBounds.minY - fixedBounds.minY
      self.var_rotation = self.var_headerRotation(self.var_offset)
      /// 触发刷新
      if !self.var_isRefreshing, self.var_offset > self.var_threshold, self.var_preOffset <= self.var_threshold {
        if (self.var_showRefresh) {
          self.var_isRefreshing = true
        }
        if nil != var_refreshTrigger && self.var_showRefresh {
          var_refreshTrigger!()
        }
      }

      if self.var_isRefreshing {
        if self.var_preOffset > self.var_threshold, self.var_offset <= self.var_threshold {
          self.var_frozen = true
        }
      } else {
        self.var_frozen = false
      }
      self.var_preOffset = self.var_offset

      //加载更多触发条件
      if (var_offDown + var_threshold <= -(self.var_preOffset - var_listH)) && var_offDown > 0 && !var_isNoMore {
        var_isMore = true
      }
    }
  }

  func var_headerRotation(_ scrollOffset: CGFloat) -> Angle {
    if scrollOffset < self.var_threshold * 0.60 {
      return .degrees(0)
    } else {
      let h = Double(self.var_threshold)
      let d = Double(scrollOffset)
      let v = max(min(d - (h * 0.6), h * 0.4), 0)
      return .degrees(180 * v / (h * 0.4))
    }
  }

  // 位置固定不变的view
  struct FixedPositionView: View {
    var body: some View {
      GeometryReader { proxy in
        Color
          .clear
          .preference(key: HTRefreshPreferenceTypes.HTRefreshPreferenceKey.self,
                      value: [HTRefreshPreferenceTypes.HTRefreshPreferenceData(var_viewType: .htEnumFixedPositionView, var_bounds: proxy.frame(in: .global))])

      }
    }
  }

  // 位置随着滑动变化的view，高度为0
  struct MovingPositionView: View {
    var body: some View {
      GeometryReader { proxy in
        Color
          .clear
          .preference(key: HTRefreshPreferenceTypes.HTRefreshPreferenceKey.self,
                      value: [HTRefreshPreferenceTypes.HTRefreshPreferenceData(var_viewType: .htEnumMovingPositionView, var_bounds: proxy.frame(in: .global))])
      }
      .frame(height: 0)
    }
  }
}

//MARK: - 下拉刷新UI
struct HTRefreshHeader: View {
  var var_height: CGFloat
  var var_loading: Bool
  var var_frozen: Bool
  var var_rotation: Angle
  var var_updateTime: Date
  let var_dateFormatter: DateFormatter = {
    let var_df = DateFormatter()
    var_df.dateFormat = "MM月dd日 HH时mm分ss秒"
    return var_df
  }()

  var body: some View {
    HStack(spacing: 20) {
      Spacer()
      Group {
        if var_loading {
          VStack {
            Spacer()
            HTActivityRep()
            Spacer()
          }
        } else {
          Image(systemName: "arrow.down")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .rotationEffect(var_rotation)
        }
      }

      .frame(width: var_height * 0.25, height: var_height * 0.8)
      .fixedSize()
      .offset(y: (var_loading && var_frozen) ? 0 : -var_height)
      VStack(spacing: 5) {
        Text("\(var_loading ? "正在刷新数据" : "下拉刷新数据")")
          .foregroundColor(.secondary)
          .font(.subheadline)
        Text("\(var_dateFormatter.string(from: var_updateTime))")
          .foregroundColor(.secondary)
          .font(.subheadline)
      }
      .offset(y: -var_height + (var_loading && var_frozen ? +var_height : 0.0))
      Spacer()
    }
    .frame(height: var_height)
  }
}

//MARK: - 加载更多UI
struct HTRefreshMore: View{
  var var_height: CGFloat

  var body: some View{
    HStack(spacing: 20) {
      Spacer()
      Group {
        VStack {
          Spacer()
          HTActivityRep()
          Spacer()
        }
      }
      .frame(width: var_height * 0.25, height: var_height * 0.8)
      .fixedSize()
      VStack() {
        Text("Loading more data")
          .foregroundColor(.secondary)
          .font(.subheadline)

      }
      Spacer()
    }
    .frame(height: var_height)
  }
}

struct HTRefreshPreferenceTypes {
  enum HTEnumViewType: Int {
    case htEnumFixedPositionView
    case htEnumMovingPositionView
  }

  struct HTRefreshPreferenceData: Equatable {
    let var_viewType: HTEnumViewType
    let var_bounds: CGRect
  }

  struct HTRefreshPreferenceKey: PreferenceKey {
    static var defaultValue: [HTRefreshPreferenceData] = []
    static func reduce(value: inout [HTRefreshPreferenceData],
                       nextValue: () -> [HTRefreshPreferenceData]) {
      value.append(contentsOf: nextValue())
    }
  }
}

struct HTActivityRep: UIViewRepresentable {
  func makeUIView(context: UIViewRepresentableContext<HTActivityRep>) -> UIActivityIndicatorView {
    return UIActivityIndicatorView()
  }
  func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<HTActivityRep>) {
    uiView.startAnimating()
  }
}
